﻿using NetDh.Lib;
using NetDh.Lib.Extensions;
using NetDh.Presentation.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace NetDh.WebApiAndMvc.Sample
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();//支持Area的Controller放在其他项目中，因为会找bin目录下所有的AreaRegistration的子类，在MapRoute时，指定namespaces。有点耗时，如果项目不使用Area，注释掉。
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new RazorViewEngine());//明确只使用RazorViewEngine引擎，否则默认还有WebFormViewEngine
            MemoryLog.Add("start!");
            SlowHttpTracer.DoLog = MemoryLog.AddWarn;//设置慢请求的记录日志方式，这边临时用MemoryLog。
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            /*
             * 不会捕获apicontroller里的代码异常，会捕获mvc controller里的代码异常
             * 当是url错误(404)时，都会捕获到。
             */
            Exception exception = Server.GetLastError();
            HttpException httpException = exception as HttpException;
            Response.Clear();
            Server.ClearError();//要清除报错，才能正常跳转到指定的错误页面。
            if (httpException != null && httpException.GetHttpCode() == 404)
            {
                //Response.Redirect("/bad/http404/");//原url会被跳转走，要在http404 Action中指定Response.StatusCode
                Response.StatusCode = (int)System.Net.HttpStatusCode.NotFound;//不指定是200
                Response.ContentType = "text/html; charset=utf-8";
                Response.WriteFile("~/badhttp/http404.html");//地址栏保留用户所输入的错误url。
            }
            else//mvc controller代码里自己抛的异常 、cshtml里的服务端代码异常等。
            {
                if (Response.StatusCode == 200) Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
                ////X-Requested-With不为null时，说明是ajax的get请求。 如果是局部页面的ajax get请求，也是走此流程。
                ////if (method == "POST" || (method == "GET" && Request.Headers["X-Requested-With"] != null))
                if (Request.IsAjaxRequest())
                {
                    //注意：如果有敏感的接口，需要在Action中try..catch返回加工过的异常信息。因为要考虑防止黑客试探异常。
                    //而一般接口没什么试探异常的价值(一般是有试探注入的价值)，因此是可以把简单异常信息返回，可以让管理员(包含前端、QA等)快速知道大体的错误原因。
                    Response.Write(exception.Message);
                }
                else
                {
                    var sampleMsg = "异常界面的测试展示信息(此消息来自于后端)：出错啦，请联系管理员！";//展示在浏览器上给用户查看的异常信息，一般需要加工过，比较友好的提醒。
                    Response.ContentType = "text/html; charset=utf-8";
                    Response.WriteFile("~/badhttp/http500.html");//地址栏保留用户所输入的url
                    Response.Write($"<script>document.getElementById('msgId').innerHTML='{sampleMsg}';</script>");
                    //Response.Redirect("~/badhttp/http500-302.html?msg=" + sampleMsg);//异常时，如果url要跳走，则用此代码。但是无法指定Response.StatusCode，只能是200.
                }
                #region 记录详细的异常信息到日志中
                StringBuilder sb = new StringBuilder();
                //TestBusinessException 业务自定义异常示例
                if (exception is TestBusinessException)
                {
                    sb.AppendLine("【TestBusinessException】");//比如，特殊异常增加特殊标识
                    //var ex = (TestBusinessException)actionExecutedContext.Exception;//是否需要使用，没使用则注释
                }
                sb.AppendLine(DateTime.Now.ToStringX());
                var ip = Request.GetClientIp();
                sb.AppendLine("【IP】:" + ip);
                sb.AppendLine($"【IsAjaxRequest】:{Request.IsAjaxRequest()} {Request.HttpMethod}");
                sb.AppendLine("【URL】:" + Request.Url);
                sb.AppendLine("【HEADER】:" + Request.Headers);
                sb.AppendLine(exception.GetAllErrorMsg());
                MemoryLog.Add(sb.ToString(), MemoryLogType.error);
                #endregion
            }
        }

        //所有api/mvc请求都会进来
        protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
        {
            try
            {
                //删除response header的敏感、非必要的信息
                HttpContext.Current.Response.Headers.Remove("X-AspNet-Version");
                HttpContext.Current.Response.Headers.Remove("X-AspNetMvc-Version");
                HttpContext.Current.Response.Headers.Remove("Server");
                //HttpContext.Current.Response.Headers.Remove("X-Powered-By"); //在这边删除无效，而是要在web.config中如下配置
                /*
                 *     <httpProtocol>
                          <customHeaders>
                            <remove name="X-Powered-By" />
                          </customHeaders>
                        </httpProtocol>
                 */
            }
            catch (Exception ex)
            {
                MemoryLog.Add("Application_PreSendRequestHeaders error:" + ex.Message, MemoryLogType.error);
            }

        }
    }
}
